package com.dylan.job.lock;

import com.dylan.job.util.SpringUtil;
import lombok.extern.slf4j.Slf4j;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

@Slf4j
public class DatabaseLock implements ILock {

    private DatabaseLock() {
        DataSource source = SpringUtil.getBean(DataSource.class);
        if (null == source) {
            throw new RuntimeException("数据库没有初始化");
        }
        this.dataSource = source;
    }

    public static DatabaseLock getLock() {
        return new DatabaseLock();
    }


    private String tableName = "xxl_job_lock";

    private String lockColumn = "lock_name";

    private String lockColumnValue = "schedule_lock";

    private DataSource dataSource;

    private transient Connection conn = null;

    private transient Boolean defaultAutoCommit = null;

    private transient PreparedStatement preparedStatement = null;

    @Override
    public void lock() {

        try {
            conn = dataSource.getConnection();
            defaultAutoCommit = conn.getAutoCommit();
            conn.setAutoCommit(false);
            String lockSql = buildLockSql();
            preparedStatement = conn.prepareStatement(lockSql);
            preparedStatement.execute();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    private String buildLockSql() {
        StringBuilder builder = new StringBuilder("select * from ")
                .append(" " + tableName)
                .append(" where ")
                .append(lockColumn)
                .append(" = ")
                .append(" '")
                .append(lockColumnValue)
                .append(" '")
                .append(" for update");
        return builder.toString();
    }

    @Override
    public void unlock() {
        // commit
        if (conn != null) {
            try {
                conn.commit();
                conn.setAutoCommit(defaultAutoCommit);
                conn.close();
            } catch (SQLException e) {
                log.error(e.getMessage(), e);
            }
        }

        // close PreparedStatement
        if (null != preparedStatement) {
            try {
                preparedStatement.close();
            } catch (SQLException e) {
                log.error(e.getMessage(), e);
            }
        }
    }
}
